﻿#ifndef __STRATEGY__
#define __STRATEGY__

#include "Input.h"
#include <bits/stdc++.h>
#include "Operation.h"
#include "Vmtype.h"
#include "ServerInstance.h"
#include "ServerType.h"
#include "Parameter.h"
#include "Output.h"

namespace hw {
    class Strategy {
    public:
        // 用于给服务器编号
        static int next_server_id();

        static int _server_id;

        static void reset_next_server_id();

    public:

        int fallback_cnt;
        int hit_cnt;
        int total;
        int K;  // 复赛的限制条件
        int day_to_read;    // 没有读取过的下一天
        int current_day;    // 当前天数
        int used_memory_day; // 已经处理过的add请求中memory总和
        int used_core_day;   // 已经处理的add请求中core总和
        int look_ahead_memory;  // 往后K天的add内存总量
        int look_ahead_core;    // 往后K天的add core总量

        std::vector<std::vector<Operation>> operation_list;
        // 虚拟机型号字符串 -> 虚拟机型号对象
        std::unordered_map<std::string, Vmtype> vm_type_dict;
        std::vector<ServerType> server_type;
        // 按照 (内存/cpu) 比例从小到大排序的服务器类型列表
        std::vector<ServerType> sorted_server_type;

        std::vector<pair<int, int>> daily_resource;   // 每天add的<core,memory>
        Parameter parameter;
        int fail_cnt;

        // 存储类型id -> 服务器类型的映射
        std::unordered_map<std::string, ServerType *> server_type_dict;
        // 用于存储已购买的服务器列表
        std::vector<ServerInstance *> server_list;

        // 存储vmid -> (vm, instance)
        std::unordered_map<std::string, std::pair<const Vmtype *, ServerInstance *>> vm_dict;

        // 用于进行输出
        Output *result;
        // 输入数据
        Input* input;

        int max_day_core, max_day_memory, day_memory, day_core;

    public:
        Strategy(Input* input, Parameter& parameter);

        void read_next_day();

        /*!
         * 处理所有的请求, 具体的处理逻辑再process中
         * @param output
         */
        void run(Output *output);

        void process();

        /*!
         * 分配一台虚拟机，如果当前已购买的服务器无法满足要求则买一台
         * @param vmid 虚拟机id
         * @param vmtype 虚拟机类型
         * @param[out] created 是否是新买的
         * @return
         */
        ServerInstance *put_vm(const string &vmid, const Vmtype &vmtype, bool &created);

        void sort_server_type();

        /*!
         * 查找能放下vmtype类型虚拟机的服务器
         * @param vmtype
         * @param[out] node 返回存放在服务器的哪个结点
         * @return 服务器对象指针
         */
        ServerInstance *find_server_for_vm(const Vmtype &vmtype, Node &node);

        /*!
         * 购买一台确保能放下vmtype类型虚拟机的服务器，其中包含了购买的策略
         * @param vmtype
         * @return 服务器对象指针
         */
        ServerInstance *purchase_server_that_fit_vm(const Vmtype &vmtype);

        /*!
         * 顺序遍历所有服务器类型，购买第一种能放下vmtype类型虚拟机的服务器
         * @param vmtype
         * @return
         */
        ServerInstance *fallback_purchase(const Vmtype &vmtype);

        /*!
         * 迁移操作
         * 每天的操作步骤是：迁移、放置和购买交替
         * 而输出顺序是：购买、迁移、放置
         * 顺序不同，所以需要将迁移的结果保存下来最后按要求顺序输出
         * 结果保存在res中
         * @param res 用于存储迁移的输出（虚拟机id, 服务器id, 服务器结点）
         */
        void migrate(vector<tuple<string, int, Node>> &res);
        void migrate_one_pass(vector<tuple<string,int,Node>>& res);


        /*!
         * 把一台vmid对应的虚拟机从origin迁移到target的node
         * @param origin
         * @param target
         * @param vmid
         * @param node
         */
        void migrate_single(ServerInstance *origin, ServerInstance *target, const string &vmid, Node node);

        void migrate_single(ServerInstance* origin, ServerInstance* target, const string& vmid);

        /*!
         * 查找vmid对应的虚拟机可以迁移到的服务器
         * @param vmtype
         * @param[out] node 迁移到哪个结点
         * @param until 查找的范围server_list[0, until)
         * @return 服务器对象
         */
        ServerInstance *find_server_for_vm_migrate(const Vmtype &vmtype, Node &node, int until);

        void migrate_fixed(vector<tuple<string, int, Node>> &res);

        void migrate_half(vector<tuple<string, int, Node>> &res);

        void migrate_new(vector<tuple<string, int, Node>> &res);

        void migrate_fixed_n(vector<tuple<string, int, Node>> &res, int n);

        void migrate_with_priority(vector<tuple<string, int, Node>> &res);

        void migrate_ultra_super_pro_max_plus(vector<tuple<string, int, Node>> &res);

        void migrate_plain(vector<tuple<string, int, Node>> &res);

        vector<pair<double, int>> split_server_by_resource(int k);

        void migrate_ultra_super_pro_max_plus(vector<tuple<string, int, Node>> &res, double d);

        void mutual_migrate(ServerInstance *instA, ServerInstance *instB, ServerInstance *mid);

        void
        mutual_migrate(ServerInstance *instA, ServerInstance *instB, ServerInstance *double_mid,
                       ServerInstance *single_mid);

        void
        mutual_migrate(ServerInstance *instA, ServerInstance *instB, ServerInstance *double_mid,
                       ServerInstance *single_mid,
                       vector<tuple<string, int, Node>> &res);
    };
} // namespace hw

#endif
